﻿using Furion.LinqBuilder;
using OAS.Application.System.Dtos;
using OAS.Core;
using OfficeOpenXml.Style;
using OfficeOpenXml;
using SqlSugar.Extensions;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Furion.FriendlyException;
using OAS.Application.UserApp.Dtos;
using OAS.Application.AttendanceApp.Dtos;
using OAS.Application.AttendanceApp.Enums;

namespace OAS.Application.AttendanceApp.Services
{
    public class AttendanceService : Repository<Attendance>, IAttendanceService, ITransient
    {
        public async Task<List<Attendance>> GetAllAttendance()
        {
            Expression<Func<Attendance, bool>> sqlWhere = Expressionable.Create<Attendance>()
                .AndIF(UserContext.CurrentUser.RoleName != "总经理" && !UserContext.IsAdmin, o => o.UserName == UserContext.CurrentUser.UserName)
                .ToExpression();
            return await AsQueryable().Where(sqlWhere).ToListAsync();
        }
        public async Task<object> GetAttendanceList(DtoQuery dto)
        {
            dto.Time = dto.Time == null ? null : TimeZoneInfo.ConvertTimeFromUtc((DateTime)dto.Time, TimeZoneInfo.Local);
            Expression<Func<Attendance, User, bool>> sqlWhere = Expressionable.Create<Attendance, User>() //创建表达式
                .AndIF(!string.IsNullOrEmpty(dto.UserName), (o, user) => o.UserName.Equals(dto.UserName))
                .AndIF(dto.Time != null, (o, user) => o.RecordDate.Value.Date.Equals(dto.Time.Value.Date))
                .AndIF(UserContext.CurrentUser.RoleName != "总经理" && UserContext.CurrentUser.RoleName != "主管" && !UserContext.IsAdmin, (o, user) => o.UserName == UserContext.CurrentUser.UserName)
                .AndIF(UserContext.CurrentUser.RoleName == "主管", (o, user) => user.Department_Id == UserContext.CurrentUser.Department_Id)
                .ToExpression();
            RefAsync<int> total = 0;
            var list = await AsQueryable()
                 .LeftJoin<User>((o, user) => o.UserName == user.UserName)
                 .Where(sqlWhere).ToPageListAsync(dto.PageIndex, dto.PageSize, total);
            return new { list, total };
        }
        public async Task UserAttendance()
        {
            var attendance = await AsQueryable().FirstAsync(o => o.UserName == UserContext.CurrentUser.UserName && o.RecordDate.Value.Date.Equals(DateTime.Now.Date));
            if (attendance is not null)
            {
                attendance.ClockOutTime = DateTime.Now;
                if (attendance.ClockInTime.Value.Hour > 9) attendance.Status = 2;
                else if (attendance.ClockInTime.Value.Hour < 6) attendance.Status = 3;
                else attendance.Status = 1;
                await base.UpdateAsync(attendance);
            }
            else
            {
                attendance = new()
                {
                    UserName = UserContext.CurrentUser.UserName,
                    ClockInTime = DateTime.Now,
                    RecordDate = DateTime.Now,
                };
                await base.InsertAsync(attendance);
            }
        }
        public async Task AddAttendance(Attendance attendance)
        {
            attendance.ClockInTime = attendance.ClockInTime == null ? null : TimeZoneInfo.ConvertTimeFromUtc((DateTime)attendance.ClockInTime, TimeZoneInfo.Local);
            attendance.ClockOutTime = attendance.ClockOutTime == null ? null : TimeZoneInfo.ConvertTimeFromUtc((DateTime)attendance.ClockOutTime, TimeZoneInfo.Local);
            attendance.RecordDate = DateTime.Now;
            await base.InsertAsync(attendance);
        }
        public async Task UpdateAttendance(Attendance attendance)
        {
            attendance.ClockInTime = attendance.ClockInTime == null ? null : TimeZoneInfo.ConvertTimeFromUtc((DateTime)attendance.ClockInTime, TimeZoneInfo.Local);
            attendance.ClockOutTime = attendance.ClockOutTime == null ? null : TimeZoneInfo.ConvertTimeFromUtc((DateTime)attendance.ClockOutTime, TimeZoneInfo.Local);
            await base.UpdateAsync(attendance);
        }
        public async Task DeleteAttendance(string[] ids)
        {
            await base.DeleteByIdsAsync(ids);
        }
        public async Task<List<DtoAttendanceExport>> GetAttendanceExport(DtoQuery dto)
        {
            dto.Time = dto.Time == null ? null : TimeZoneInfo.ConvertTimeFromUtc((DateTime)dto.Time, TimeZoneInfo.Local);
            Expression<Func<Attendance, User, bool>> sqlWhere = Expressionable.Create<Attendance, User>() //创建表达式
                .AndIF(!string.IsNullOrEmpty(dto.UserName), (o, user) => o.UserName.Equals(dto.UserName))
                .AndIF(dto.Time != null, (o, user) => o.RecordDate.Value.Date.Equals(dto.Time.Value.Date))
                .AndIF(UserContext.CurrentUser.RoleName != "总经理" && UserContext.CurrentUser.RoleName != "主管" && !UserContext.IsAdmin, (o, user) => o.UserName == UserContext.CurrentUser.UserName)
                .AndIF(UserContext.CurrentUser.RoleName == "主管", (o, user) => user.Department_Id == UserContext.CurrentUser.Department_Id)
                .ToExpression();
            return await AsQueryable().LeftJoin<User>((o, user) => o.UserName == user.UserName).Where(sqlWhere)
            .Select((o, user) => new DtoAttendanceExport
            {
                UserName = o.UserName,
                UserTrueName = user.UserTrueName,
                RecordDate = ((DateTime)o.RecordDate).ToString("yyyy-MM-dd"),
                ClockInTime = ((DateTime)o.ClockInTime).ToString("HH:mm"),
                ClockOutTime = ((DateTime)o.ClockOutTime).ToString("HH:mm"),
                Status = o.Status
            }).Mapper(o => {
                o.StatusName = o.Status is null ? "" : Enum.GetName(typeof(AttendanceStatus), o.Status);
            }).ToListAsync();
        }
    }
}
